const zbList = function() {
    this.onRender = null;//调用this.show方法后执行
    this.content = '';

    this.tplAction =
        '<div class="zb-list" id="{list_id}">\
            <div class="item" id="{item_id}" onclick="{func}(this)" data-params="{params}">\
                <div class="title">{title}</div>\
                <div class="body">\
                    <div class="desc">{desc}</div>\
                    <div class="action zb-icon-right-arrow">&nbsp;</div>\
                </div>\
            </div>\
        </div>';

    this.tplClick =
        '<div class="zb-list" id="{list_id}">\
            <div class="item" id="{item_id}" onclick="{onclick}">\
                <div class="title">{title}</div>\
                <div class="body">\
                    <div class="desc">{desc}</div>\
                    <div class="action zb-icon-right-arrow">&nbsp;</div>\
                </div>\
            </div>\
        </div>';

    this.tplText =
        '<div class="zb-list" id="{list_id}">\
            <div class="item" id="{item_id}">\
                <div class="title">{title}</div>\
                <div class="body">\
                    <div class="desc">{desc}</div>\
                </div>\
            </div>\
        </div>';

    this.initCss = function() {
        let flag = document.getElementsByClassName('zb-list');
        if (!flag || flag.length === 0) {
            let style = document.createElement('style');
            style.innerText =
                '.hide{display:none}'+
                '.show{display:block}'+
                '.zb-icon-right-arrow {background-image: url(\'\'); background-size: 100% 100%; background-repeat: no-repeat;}' +
                '.zb-list {}' +
                '.zb-list .item {display: flex; flex-direction: row; justify-content: space-between; align-items: center; border-bottom: 1px solid #c8c8c8; margin: 3px 1px; padding:3px 2px;}' +
                '.zb-list .item .title {}' +
                '.zb-list .item .body {display: flex; flex-direction: row; justify-content: flex-start; align-items: center}' +
                '.zb-list .item .desc {flex-grow: 1; text-align: right; overflow: hidden; white-space: nowrap; text-overflow:ellipsis;font-size: 14px; color: #888888; padding-right: 5px;}' +
                '.zb-list .item .action {width: 18px;}' +
                ''
            ;

            let head = document.getElementsByTagName('head')[0];
            head.appendChild(style);
        }
    }

    //初始化
    this.init = function(data, config){
        this.initCss();

        let list_type = config['list_type'];
        let list_id = config['list_id'];
        let node = '';
        let list_data = '';
        switch (list_type) {
            case 'action':
                node = this.htmlToNode(this.tplAction);
                list_data = [{list_id: list_id, item: data}];
                this.content = this.repeatNode(node, list_data);
                break;
            case 'click' :
                node = this.htmlToNode(this.tplClick);
                list_data = [{list_id: list_id, item: data}];
                this.content = this.repeatNode(node, list_data);
                break;
            default:
                this.content = '';
                break;
        }
    }

    //将内容覆盖到某个元素中
    this.show = function(id) {
        document.getElementById(id).innerHTML = this.content;
        if (typeof this.onRender === 'function') {
            this.onRender();
        }
    }

    //追加panel到列表中
    this.append = function(data, config) {
        let list = document.getElementById(config['list_id']);
        let tpl = this.getTpl(config['list_type']);
        let node = this.htmlToNode(tpl);
        let str = node.getElementsByClassName('item')[0].outerHTML;

        //data中的zb-panel-box需要是数组, 表示有多个panel
        for (let i=0; i<data.length; i++) {
            let tmp_str = this.repeatString(str, [data[i]]);
            let tmp_node = this.htmlToNode(tmp_str);
            list.append(tmp_node)
        }
    }

    this.encodeObj = function (obj) {
        return encodeURIComponent(JSON.stringify(obj));
    }

    this.decodeObj = function (str) {
        return JSON.parse(decodeURIComponent(str));
    }

    this.htmlToNode = function(html) {
        let div = document.createElement('div');
        div.innerHTML = html;
        return div.firstElementChild;
    }

    this.repeatString = function (tplDom, arr, func=null) {
        if (tplDom.length === 0) {
            this.error('字符串长度为空');
            return;
        }

        if (arr.length === 0) {
            this.error('数据为空');
            return tplDom;
        }

        let tpl = tplDom;
        let out = '';
        for (let i=0; i<arr.length; i++) {
            if (typeof func === 'function') {
                arr[i] = func(arr[i]);
            }
            let map = arr[i];
            let tmp = tpl;
            for (let j in map) {
                let re = new RegExp('{' + j + '}', 'g');
                tmp = tmp.replace(re, map[j]);
            }

            let re = new RegExp('{_idx}', 'g');
            tmp = tmp.replace(re, parseInt(i)+1);

            out += tmp;
        }

        return out;
    };

    /**
     * @param node HTML DOM节点, 注意不是string
     * @param arr json数组 注意是数组类型
     * @return string 返回HTML字符串, 注意不是DOM节点
     */
    this.repeatNode = function (node, arr) {
        let out = [];
        for (let i=0; i<arr.length; i++) {
            let tmp = node.outerHTML;
            tmp = tmp.replace(/\s/g, ' '); //去掉回车换行, 减少空白符

            let map = arr[i];

            //先渲染内层的数组
            for (let j in map) {
                if (map[j] instanceof Array) { //数组, 递归替换
                    let subNode = node.querySelector('.'+j);
                    if (subNode) {
                        let subHtml = this.repeatNode(subNode, map[j]); //递归
                        let subTpl = subNode.outerHTML.replace(/\s/g, ' ');
                        tmp = tmp.replace(subTpl, subHtml);
                    }
                }
            }

            //再渲染内层的对象
            for (let j in map) {
                if (map[j] instanceof Object && !(map[j] instanceof Array)) { //对象, 递归替换
                    let subNode = node.querySelector('.'+j);
                    if (subNode) {
                        let subHtml = this.repeatNode(subNode, [map[j]]); //递归
                        let subTpl = subNode.outerHTML.replace(/\s/g, ' ')
                        tmp = tmp.replace(subTpl, subHtml);
                    }
                }
            }

            //最后渲染外层的键值对/字符串
            for (let j in map) {
                if (typeof map[j] === 'string' || typeof map[j] === 'number') { //字符串, 直接替换
                    let re = new RegExp('{' + j + '}', 'g');
                    tmp = tmp.replace(re, map[j]);
                }
            }

            out.push(tmp);
        }

        return out.join('');
    }

    this.error = function (str){
        console.log('zbList Error: '+str)
    }

}

/**
 let mylist = new zbList();
 let config = {list_id:'mylist', list_type:'click'};
 let data = [
     {
        'item_id': '1111',
        'title':'测试-name1',
        'desc': '<p>Hello World!</p>',
        'params': 'xxx',
        'func': 'callback_name'
    },
     {
        'item_id': '2222',
        'title':'测试-name2',
        'desc': '<p>Hello World!</p>',
        'params': 'xxx',
        'func': 'callback_name'
    },
 ]
 mylist.init(data,config);

 mylist.onRender = function() {

		}
 mylist.show('aaa');

 let children = [
     {
        'item_id': '3333',
        'title':'测试-name3',
        'desc': '<p>Hello World!</p>',
        'params': 'xxx',
        'func': 'callback_name'
    },
     {
        'item_id': '4444',
        'title':'测试-name4',
        'desc': '<p>Hello World!</p>',
        'params': 'xxx',
        'func': 'callback_name'
    },
 ];
 mylist.append(children, config);
 */